package com.pf.utils;

import com.google.common.collect.Lists;
import com.pf.dto.UserScore;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**
 * @author PF
 * @date 2021/7/1 21:24
 * @Version 1.0
 */
@Slf4j
public class ExcelUtils {

    /**
     * 获取excel数据
     *
     * @return
     */
    public static List<UserScore> getExcelData() {
        UserScore userScore = UserScore.builder().id(1).subject("数学").score(120).build();
        UserScore userScore2 = UserScore.builder().id(2).subject("英语").score(130).build();
        UserScore userScore3 = UserScore.builder().id(3).subject("语文").score(130).build();
        List<UserScore> userScores = Lists.newArrayList(userScore, userScore2, userScore3);
        return userScores;
    }

    /**
     * 创建excel，以输出流形式返回
     * <p>
     * 场景1：在后端生成excel，并保存到对应某个目录。（这种一般不实用）
     * 场景2：在后端生成excel，然后通过浏览器请求下载。（下载excel时，经常会用到）
     * 场景3：在后端生成excel，并发送邮件
     * <p>
     * 本案例：主要讨论场景3.
     * 思路：
     * 1）poi的 SXSSFWorkbook 对象 write方法，接收的参数是输出流（OutputStream抽象类）
     * 2）发邮件使用的Spring框架的MimeMessageHelper对象，接收的参数是输入流（InputStreamSource抽象类）
     * 3）把OutputStream转换成InputStreamSource，可借助 ByteArrayOutputStream 类。本方法就是这样实现的
     *
     * @return
     */
    public static byte[] createExcel() {

        // 创建一个SXSSFWorkbook
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        // 创建sheet页
        Sheet sheet = workbook.createSheet();

        // 创建表头
        Row headRow = sheet.createRow(0);
        String[] headTitles = {"id", "科目", "成绩"};
        for (int i = 0; i < headTitles.length; i++) {
            headRow.createCell(i).setCellValue(headTitles[i]);
        }

        // 创建数据内容
        List<UserScore> excelData = getExcelData();
        for (int m = 0; m < excelData.size(); m++) {
            UserScore userScore = excelData.get(m);
            Row row = sheet.createRow(m + 1);
            for (int n = 0; n < headTitles.length; n++) {
                switch (n) {
                    case 0:
                        row.createCell(n).setCellValue(userScore.getId());
                        break;
                    case 1:
                        row.createCell(n).setCellValue(userScore.getSubject());
                        break;
                    case 2:
                        row.createCell(n).setCellValue(userScore.getScore());
                        break;
                }
            }
        }

        ByteArrayOutputStream baos = null;
        OutputStream os = null;
        try {
            // 创建ByteArray输出流，ByteArrayOutputStream中也有一个内部缓冲区，当数据写入是缓冲区会自动增长，内部有一个计数器来记录缓冲区的字节数。主要的方法和OutputStream类似
            baos = new ByteArrayOutputStream();
            // 构造一个字节缓冲输出流对象
            os = new BufferedOutputStream(baos);
            // 把SXSSFWorkbook内容写入ByteArray输出流中
            workbook.write(os);
            // 清空缓存区
            os.flush();
            return baos.toByteArray();
        } catch (Exception e) {
            log.error("ExcelUtils createExcel error", e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
